﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Reflection;
using Newtonsoft.Json.Linq;

namespace DidaManager.Models.JsonConvert
{
    /// <summary>
    /// 变量配置下载文件模型与读写工具
    /// </summary>
    public class VarConfigToConfigFile
    {
        [JsonPropertyName("VARConfigs")]
        public List<VarConfigGroup> VARConfigs { get; set; } = new List<VarConfigGroup>();

        public static void ExportToExcel(string filePath)
        {

        }

        /// <summary>
        /// 从 JSON 文件反序列化为 VarConfigToConfigFile
        /// </summary>
        public static VarConfigToConfigFile ParseFromJson(string filePath)
        {
            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException($"文件不存在: {filePath}");
            }

            string jsonString = File.ReadAllText(filePath);
            if (string.IsNullOrWhiteSpace(jsonString))
            {
                throw new ArgumentException("JSON内容不能为空");
            }

            var options = new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true
            };

            return JsonSerializer.Deserialize<VarConfigToConfigFile>(jsonString, options) ?? new VarConfigToConfigFile();
        }

        /// <summary>
        /// 将 VarConfigToConfigFile 序列化保存为 JSON 文件
        /// </summary>
        public static void SaveToJson(VarConfigToConfigFile config, string filePath)
        {
            string jsonContent = JsonSerializer.Serialize(config, JsonSerializerOptionsManager.Compact);
            File.WriteAllText(filePath, jsonContent, new UTF8Encoding(false));
        }

        /// <summary>
        /// 从数据库导出的 JSON（或已是下载格式的 JSON）解析并保存为下载格式
        /// </summary>
        public static void ParseDbJsonAndSave(string filePath)
        {
            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException($"文件不存在: {filePath}");
            }

            string jsonContent = File.ReadAllText(filePath, new UTF8Encoding(false));
            if (string.IsNullOrWhiteSpace(jsonContent))
            {
                throw new ArgumentException("JSON内容不能为空");
            }

            // 检测是否为数据库格式（VarList 中的项包含 extra 字段）
            try
            {
                var root = JObject.Parse(jsonContent);
                var firstVar = root["VARConfigs"]?.First?
                                .Value<JObject>()?["VarList"]?.First?
                                .Value<JObject>();
                bool isDbFormat = firstVar != null && firstVar.ContainsKey("extra");

                if (isDbFormat)
                {
                    // 数据库JSON -> 下载格式
                    var dbRoot = MapJsonToObject<DatabaseVarRoot>(root);
                    var download = ConvertToDownloadFormat(dbRoot);
                    SaveToJson(download, filePath);
                    return;
                }
            }
            catch
            {
                // 解析失败则尝试按下载格式读取并规范化保存
            }

            // 已是下载格式则规范化缩进保存
            var config = ParseFromJson(filePath);
            SaveToJson(config, filePath);
        }

        // ========== DB -> 下载格式转换逻辑 ==========

        private static VarConfigToConfigFile ConvertToDownloadFormat(DatabaseVarRoot dbRoot)
        {
            var result = new VarConfigToConfigFile
            {
                VARConfigs = new List<VarConfigGroup>()
            };

            if (dbRoot.VARConfigs == null)
            {
                return result;
            }

            foreach (var dbGroup in dbRoot.VARConfigs)
            {
                var group = new VarConfigGroup
                {
                    PortName = dbGroup.PortName ?? string.Empty,
                    DevName = dbGroup.DevName ?? string.Empty,
                    VarList = new List<VarItem>()
                };

                if (dbGroup.VarList != null)
                {
                    foreach (var dbItem in dbGroup.VarList)
                    {
                        var item = new VarItem
                        {
                            Id = dbItem.Id,
                            Name = dbItem.Name ?? string.Empty,
                            DataType = GetDataType(dbItem),
                            Decimal = GetDecimalPlaces(dbItem),
                            Unit = dbItem.Extra?.Unit ?? string.Empty,
                            Modulus = dbItem.Extra?.ConversionFactor ?? 0,
                            ReadWrite = (int)(dbItem.Extra?.General?.TypeRW??0),
                            AnotherName = dbItem.Extra?.Alias ?? string.Empty,
                            OpcVarPath = dbItem.Extra?.OpcVarPath ?? string.Empty,
                            SignalType = MapSignalType(dbItem.Extra?.Hj212?.SignalType),
                            UpRangeValue = ParseNullableDouble(dbItem.Extra?.Hj212?.RangeUpper),
                            DownRangeValue = ParseNullableDouble(dbItem.Extra?.Hj212?.RangeLower),
                            Offset = dbItem.Extra?.Offset ?? 0,
                            Param = new VarParam
                            {
                                RegAddr = ParseUint(dbItem.Extra?.General?.Address) ?? 0,
                                RegType = GetRegType(dbItem),
                                Command = dbItem.Extra?.Protocol?.General?.QueryCommand ?? string.Empty,
                                MarkStart = dbItem.Extra?.Protocol?.General?.MessageStart ?? string.Empty,
                                StartByte = ParseUint(dbItem.Extra?.Protocol?.General?.ValueStartByte) ?? 0,
                                ByteSize = ParseUint(dbItem.Extra?.Protocol?.General?.DataLength) ?? 0,
                            },
                            Event = new VarEvent
                            {
                                EventName = dbItem.Extra?.Alarm?.EventIdentifier ?? string.Empty,
                                MathType = GetEventType(dbItem),
                                MathValue = ParseBool(dbItem.Extra?.Alarm?.ConditionValue)
                            },
                            Dlt645 = new ProtocolLt645
                            {
                                //RuleCategory = dbItem.Extra?.Protocol?.Lt645?.RuleCategory ?? string.Empty,
                                RuleCategory = string.Empty,
                                RuleId = GetDlt645Type(dbItem)
                            }
                        };

                        group.VarList.Add(item);
                    }
                }

                result.VARConfigs.Add(group);
            }

            return result;
        }

        private static int GetRegType(DatabaseVarItem dbItem)
        {
            if (dbItem.Extra != null && dbItem.Extra.General != null)
            {
                string? type = dbItem.Extra?.General?.Type;
                if (string.IsNullOrWhiteSpace(type)) return 0;
                return DeviceRegisterConfigManager.GetRegisterIdByName(type);
            }
            return 0;
        }

        private static int GetDataType(DatabaseVarItem dbItem)
        {
            // 优先使用 extra.data_type（数值型），否则尝试根据字符串 dataType 简单映射
            //if (dbItem.Extra != null)
            //{
            //    if (dbItem.Extra.DataTypeNum.HasValue)
            //    {
            //        return dbItem.Extra.DataTypeNum.Value;
            //    }
            //}

            if (dbItem.Extra == null)
            {
                return 0;
            }

            var s = dbItem.Extra.DataTypeStr?.Trim()?.ToLowerInvariant();
            return s switch
            {
                "bool" => 1,
                "uint16" => 2,
                "uint32" => 3,
                "uint64" => 4,
                "int16" => 5,
                "int32" => 6,
                "int64" => 7,
                "float" => 8,
                "double" => 9,
                "string" => 10,
                "byte" => 11,
                "bit" => 12,
                _ => 0
            };
        }

        private static int GetEventType(DatabaseVarItem dbItem)
        {
            // 优先使用 extra.data_type（数值型），否则尝试根据字符串 dataType 简单映射
            if (dbItem.Extra != null && dbItem.Extra.Alarm != null)
            {
                var s = dbItem.Extra.Alarm.ConditionOperator?.Trim()?.ToLowerInvariant();
                return s switch
                {
                    ">" => 0,
                    ">=" => 1,
                    "<" => 2,
                    "<=" => 3,
                    "==" => 4,
                    "!=" => 5,
                    _ => 0
                };
            }

            return 0; // 默认值
        }
        private static string GetDlt645Type(DatabaseVarItem dbItem)
        {
            // 优先使用 extra.data_type（数值型），否则尝试根据字符串 dataType 简单映射
            if (dbItem.Extra != null && dbItem.Extra.Protocol != null)
            {
                var strRuleCategory = dbItem.Extra.Protocol.Lt645?.RuleCategory?.Trim()?.ToLowerInvariant();
                var strRuleId = dbItem.Extra.Protocol.Lt645?.RuleId?.Trim()?.ToLowerInvariant();

                if (string.IsNullOrWhiteSpace(strRuleCategory)) return string.Empty;
                if (string.IsNullOrWhiteSpace(strRuleId)) return string.Empty;

                return Dlt645Config.GetDlt645TypeId(strRuleCategory,strRuleId);
            }
            
            return string.Empty; // 默认值
        }


        private static int GetDecimalPlaces(DatabaseVarItem dbItem)
        {
            if (dbItem.Extra != null)
            {
                // 优先 extra.decimal
                if (dbItem.Extra.DecimalPlaces.HasValue) return dbItem.Extra.DecimalPlaces.Value;
            }
            return dbItem.DecimalPlaces ?? 0;
        }

        private static int MapSignalType(string? st)
        {
            if (string.IsNullOrWhiteSpace(st)) return 0;
            switch (st.Trim().ToLowerInvariant())
            {
                case "analog":
                case "ai":
                case "an":
                    return 0;
                case "digital":
                case "di":
                case "switch":
                    return 1;
                default:
                    return 0;
            }
        }

        private static double? ParseNullableDouble(string? s)
        {
            if (string.IsNullOrWhiteSpace(s)) return null;
            if (double.TryParse(s, out var v)) return v;
            return null;
        }

        private static bool ParseBool(string? s)
        {
            if (string.IsNullOrWhiteSpace(s)) return false;
            if (bool.TryParse(s, out var b)) return b;
            if (int.TryParse(s, out var i)) return i != 0;
            return false;
        }

        private static int? ParseUint(string? s)
        {
            if (string.IsNullOrWhiteSpace(s)) return null;
            if (int.TryParse(s, out var v)) return v;
            return null;
        }

        // 简单的 JSON -> 对象映射（与其它转换类保持一致风格）
        private static T MapJsonToObject<T>(JObject json) where T : class, new()
        {
            var obj = new T();
            var properties = typeof(T).GetProperties();

            foreach (var prop in properties)
            {
                var jsonPropertyName = GetJsonPropertyName(prop);
                if (json.TryGetValue(jsonPropertyName, out JToken? value) && value != null)
                {
                    SetPropertyValue(obj, prop, value);
                }
            }

            return obj;
        }

        // 重载方法，支持动态类型
        private static object? MapJsonToObject(Type type, JObject json)
        {
            var obj = Activator.CreateInstance(type);
            if (obj == null) return null;

            var properties = type.GetProperties();
            foreach (var prop in properties)
            {
                var jsonPropertyName = GetJsonPropertyName(prop);
                if (json.TryGetValue(jsonPropertyName, out JToken? value) && value != null)
                {
                    SetPropertyValue(obj, prop, value);
                }
            }

            return obj;
        }

        private static string GetJsonPropertyName(PropertyInfo prop)
        {
            var attr = prop.GetCustomAttribute<JsonPropertyNameAttribute>();
            return attr?.Name ?? prop.Name;
        }

        private static void SetPropertyValue(object obj, PropertyInfo prop, JToken value)
        {
            if (obj == null) return;

            try
            {
                if (prop.PropertyType == typeof(string))
                {
                    prop.SetValue(obj, value.ToString());
                    return;
                }
                if (prop.PropertyType == typeof(int))
                {
                    if (value.Type == JTokenType.Integer)
                    {
                        prop.SetValue(obj, value.Value<int>());
                    }
                    else
                    {
                        int.TryParse(value.ToString(), out int v);
                        prop.SetValue(obj, v);
                    }
                    return;
                }
                if (prop.PropertyType == typeof(int?))
                {
                    if (value.Type == JTokenType.Null)
                    {
                        prop.SetValue(obj, null);
                        return;
                    }
                    if (value.Type == JTokenType.Integer)
                    {
                        prop.SetValue(obj, (int?)value.Value<int>());
                    }
                    else if (int.TryParse(value.ToString(), out int v))
                    {
                        prop.SetValue(obj, (int?)v);
                    }
                    else
                    {
                        prop.SetValue(obj, null);
                    }
                    return;
                }
                if (prop.PropertyType == typeof(bool))
                {
                    if (value.Type == JTokenType.Boolean)
                    {
                        prop.SetValue(obj, value.Value<bool>());
                    }
                    else
                    {
                        bool.TryParse(value.ToString(), out bool b);
                        prop.SetValue(obj, b);
                    }
                    return;
                }
                if (prop.PropertyType == typeof(double?))
                {
                    if (value.Type == JTokenType.Null)
                    {
                        prop.SetValue(obj, null);
                        return;
                    }
                    if (double.TryParse(value.ToString(), out var d))
                    {
                        prop.SetValue(obj, (double?)d);
                    }
                    else
                    {
                        prop.SetValue(obj, null);
                    }
                    return;
                }
                if (typeof(System.Collections.IEnumerable).IsAssignableFrom(prop.PropertyType) && prop.PropertyType != typeof(string))
                {
                    // 处理集合类型
                    if (value is JArray array && prop.PropertyType.IsGenericType)
                    {
                        var elementType = prop.PropertyType.GetGenericArguments()[0];
                        var listType = typeof(List<>).MakeGenericType(elementType);
                        var list = Activator.CreateInstance(listType);
                        
                        if (list != null)
                        {
                            var addMethod = listType.GetMethod("Add");
                            foreach (var item in array)
                            {
                                object? element = null;
                                
                                if (elementType == typeof(string))
                                {
                                    element = item.ToString();
                                }
                                else if (elementType == typeof(int))
                                {
                                    if (int.TryParse(item.ToString(), out int intVal))
                                        element = intVal;
                                }
                                else if (elementType == typeof(double))
                                {
                                    if (double.TryParse(item.ToString(), out double doubleVal))
                                        element = doubleVal;
                                }
                                else if (elementType == typeof(bool))
                                {
                                    if (bool.TryParse(item.ToString(), out bool boolVal))
                                        element = boolVal;
                                }
                                else if (elementType.IsClass && item is JObject itemObj)
                                {
                                    // 递归处理复杂对象
                                    element = MapJsonToObject(elementType, itemObj);
                                }
                                
                                if (element != null)
                                {
                                    addMethod?.Invoke(list, new[] { element });
                                }
                            }
                            
                            prop.SetValue(obj, list);
                        }
                    }
                    return;
                }
                if (prop.PropertyType.IsClass && prop.PropertyType != typeof(string))
                {
                    if (value is JObject nested)
                    {
                        var nestedObj = Activator.CreateInstance(prop.PropertyType);
                        if (nestedObj != null)
                        {
                            foreach (var nestedProp in prop.PropertyType.GetProperties())
                            {
                                var name = GetJsonPropertyName(nestedProp);
                                if (nested.TryGetValue(name, out var nv) && nv != null)
                                {
                                    SetPropertyValue(nestedObj, nestedProp, nv);
                                }
                            }
                            prop.SetValue(obj, nestedObj);
                        }
                    }
                    return;
                }
            }
            catch
            {
                // 忽略，保持默认值
            }
        }
    }

    public class VarConfigGroup
    {
        [JsonPropertyName("VarList")]
        public List<VarItem> VarList { get; set; } = new List<VarItem>();

        [JsonPropertyName("PortName")]
        public string PortName { get; set; } = string.Empty;

        [JsonPropertyName("DevName")]
        public string DevName { get; set; } = string.Empty;
    }

    public class VarItem
    {
        [JsonPropertyName("Name")]
        public string Name { get; set; } = string.Empty;

        [JsonPropertyName("DataType")]
        public int DataType { get; set; }

        [JsonPropertyName("Decimal")]
        public int Decimal { get; set; }

        [JsonPropertyName("Unit")]
        public string Unit { get; set; } = string.Empty;

        [JsonPropertyName("Modulus")]
        public int Modulus { get; set; }

        [JsonPropertyName("Offset")]
        public int Offset { get; set; }

        [JsonPropertyName("readWrite")]
        public int ReadWrite { get; set; }

        [JsonPropertyName("AnotherName")]
        public string AnotherName { get; set; } = string.Empty;

        [JsonPropertyName("OpcVarPath")]
        public string OpcVarPath { get; set; } = string.Empty;

        [JsonPropertyName("SignalType")]
        public int SignalType { get; set; }

        [JsonPropertyName("UpRangeValue")]
        public double? UpRangeValue { get; set; }

        [JsonPropertyName("DownRangeValue")]
        public double? DownRangeValue { get; set; }

        [JsonPropertyName("id")]
        public int Id { get; set; }

        [JsonPropertyName("Param")]
        public VarParam Param { get; set; } = new VarParam();

        [JsonPropertyName("Event")]
        public VarEvent Event { get; set; } = new VarEvent();

        [JsonPropertyName("Dlt645")]
        public ProtocolLt645 Dlt645 { get; set; } = new ProtocolLt645();
    }

    public class VarParam
    {
        [JsonPropertyName("RegAddr")]
        public int RegAddr { get; set; }

        [JsonPropertyName("RegType")]
        public int RegType { get; set; }

        [JsonPropertyName("Command")]
        public string Command { get; set; } = string.Empty;

        [JsonPropertyName("MarkStart")]
        public string MarkStart { get; set; } = string.Empty;

        [JsonPropertyName("StartByte")]
        public int StartByte { get; set; }

        [JsonPropertyName("ByteSize")]
        public int ByteSize { get; set; }
    }

    public class VarEvent
    {
        [JsonPropertyName("EventName")]
        public string EventName { get; set; } = string.Empty;

        [JsonPropertyName("MathType")]
        public int MathType { get; set; }

        [JsonPropertyName("MathValue")]
        public bool MathValue { get; set; }
    }

    public class ProtocolLt645
    {
        [JsonPropertyName("RuleCategory")]
        public string? RuleCategory { get; set; }

        [JsonPropertyName("RuleId")]
        public string? RuleId { get; set; }
    }
    // ========== 数据库JSON结构定义 + 反射映射工具 ==========

    public class DatabaseVarRoot
    {
        [JsonPropertyName("VARConfigs")]
        public List<DatabaseVarGroup> VARConfigs { get; set; } = new List<DatabaseVarGroup>();
    }

    public class DatabaseVarGroup
    {
        [JsonPropertyName("VarList")]
        public List<DatabaseVarItem> VarList { get; set; } = new List<DatabaseVarItem>();

        [JsonPropertyName("PortName")]
        public string PortName { get; set; } = string.Empty;

        [JsonPropertyName("DevName")]
        public string DevName { get; set; } = string.Empty;
    }

    public class DatabaseVarItem
    {
        [JsonPropertyName("id")]
        public int Id { get; set; }

        [JsonPropertyName("name")]
        public string Name { get; set; } = string.Empty;

        [JsonPropertyName("monitor_device_id")]
        public int MonitorDeviceId { get; set; }

        // 原始项级字段（可选）
        [JsonPropertyName("dataType")]
        public string? DataTypeStr { get; set; }

        [JsonPropertyName("decimalPlaces")]
        public int? DecimalPlaces { get; set; }

        [JsonPropertyName("extra")]
        public DatabaseVarExtra? Extra { get; set; }
    }

    public class DatabaseVarExtra
    {
        [JsonPropertyName("alias")]
        public string? Alias { get; set; }

        [JsonPropertyName("dataType")]
        public string? DataTypeStr { get; set; }

        [JsonPropertyName("decimalPlaces")]
        public int? DecimalPlaces { get; set; }

        [JsonPropertyName("conversionFactor")]
        public int? ConversionFactor { get; set; }

        [JsonPropertyName("offset")]
        public int? Offset { get; set; }

        [JsonPropertyName("data_type")]
        public int? DataTypeNum { get; set; }

        [JsonPropertyName("decimal")]
        public int? Decimal { get; set; }

        [JsonPropertyName("unit")]
        public string? Unit { get; set; }

        [JsonPropertyName("modulus")]
        public int? Modulus { get; set; }

        [JsonPropertyName("content_value")]
        public string? ContentValue { get; set; }

        [JsonPropertyName("formula")]
        public string? Formula { get; set; }

        [JsonPropertyName("opc_var_path")]
        public string? OpcVarPath { get; set; }

        [JsonPropertyName("alarm")]
        public DatabaseAlarm? Alarm { get; set; }

        [JsonPropertyName("hj212")]
        public DatabaseVarHj212? Hj212 { get; set; }

        [JsonPropertyName("protocol")]
        public DatabaseProtocol? Protocol { get; set; }

        [JsonPropertyName("frame")]
        public DatabaseFrame? Frame { get; set; }

        [JsonPropertyName("regTypeEx")]
        public DatabaseRegTypeEx? RegTypeEx { get; set; }

        [JsonPropertyName("general")]
        public DatabaseGeneral? General { get; set; }
    }

    public class DatabaseAlarm
    {
        [JsonPropertyName("conditionOperator")]
        public string? ConditionOperator { get; set; }

        [JsonPropertyName("conditionValue")]
        public string? ConditionValue { get; set; }

        [JsonPropertyName("eventIdentifier")]
        public string? EventIdentifier { get; set; }
    }

    public class DatabaseVarHj212
    {
        [JsonPropertyName("signalType")]
        public string? SignalType { get; set; }

        [JsonPropertyName("rangeUpper")]
        public string? RangeUpper { get; set; }

        [JsonPropertyName("rangeLower")]
        public string? RangeLower { get; set; }
    
        [JsonPropertyName("alarmUpper")]
        public string? AlarmUpper { get; set; }

        [JsonPropertyName("alarmLower")]
        public string? AlarmLower { get; set; }

        [JsonPropertyName("reportConfig")]
        public List<object>? ReportConfig { get; set; }
    }

    public class DatabaseProtocol
    {
        [JsonPropertyName("type")]
        public string? Type { get; set; }

        [JsonPropertyName("general")]
        public DatabaseProtocolGeneral? General { get; set; }

        [JsonPropertyName("lt645")]
        public DatabaseProtocolLt645? Lt645 { get; set; }
    }

    public class DatabaseProtocolGeneral
    {
        [JsonPropertyName("queryCommand")]
        public string? QueryCommand { get; set; }

        [JsonPropertyName("messageStart")]
        public string? MessageStart { get; set; }

        [JsonPropertyName("valueStartByte")]
        public string? ValueStartByte { get; set; }

        [JsonPropertyName("dataLength")]
        public string? DataLength { get; set; }
    }

    public class DatabaseProtocolLt645
    {
        [JsonPropertyName("ruleCategory")]
        public string? RuleCategory { get; set; }

        [JsonPropertyName("ruleId")]
        public string? RuleId { get; set; }
    }

    public class DatabaseFrame
    {
        [JsonPropertyName("tx_rule")]
        public string? TxRule { get; set; }
    }

    public class DatabaseRegTypeEx
    {
        [JsonPropertyName("DBNum")]
        public string? DBNum { get; set; }

        [JsonPropertyName("RegAddr")]
        public string? RegAddr { get; set; }

        [JsonPropertyName("BitAddr")]
        public string? BitAddr { get; set; }

        [JsonPropertyName("RegTypeEx")]
        public int? RegTypeEx { get; set; }
    }

    public class DatabaseGeneral
    {
        [JsonPropertyName("type")]
        public string? Type { get; set; }

        [JsonPropertyName("type_rw")]
        public int TypeRW { get; set; }

        [JsonPropertyName("address")]
        public string? Address { get; set; }

        [JsonPropertyName("isHex")]
        public bool? IsHex { get; set; }
    }
}
